package cmode

import (
	"errors"
	"fmt"
	"io"
	"strconv"
	"strings"

	hostlink "gitee.com/acquisition_driver_development/magus_iot/common_library/hostlink_0903"
	"gitee.com/acquisition_driver_development/magus_iot/magus/golib/sock"
	"gitee.com/acquisition_driver_development/magus_iot/magus/logs"
)

type CmodeMaster struct {
	hostlink.Master
	UintNum string //目标单元号
}

func (this *CmodeMaster) Initialize(da2 string) (err error) {
	if strings.TrimSpace(da2) == "" {
		this.UintNum = "00"
	}
	dint, err := strconv.ParseUint(da2, 10, 32)
	if err != nil || dint > 31 {
		err = errors.New("unknown unitnumber: " + da2)
		return
	}
	switch len(da2) {
	case 1:
		this.UintNum = "0" + da2
	case 2:
		this.UintNum = da2
	default:
		err = errors.New("unknown unitnumber: " + da2)
		return
	}

	this.Master.Initialize()
	return
}

func (this *CmodeMaster) MakeRequest(group *hostlink.Group) (cmd []byte) {

	cmd = []byte(hostlink.HK_TITLE + this.UintNum + group.WordCode)
	data := make([]byte, 8)
	data[0] = byte(group.BeginAddress/1000) + byte(0x30)
	data[1] = byte(group.BeginAddress%1000/100) + byte(0x30)
	data[2] = byte(group.BeginAddress%1000%100/10) + byte(0x30)
	data[3] = byte(group.BeginAddress%1000%100%10) + byte(0x30)

	data[4] = byte(group.Size/1000) + byte(0x30)
	data[5] = byte(group.Size%1000/100) + byte(0x30)
	data[6] = byte(group.Size%1000%100/10) + byte(0x30)
	data[7] = byte(group.Size%1000%100%10) + byte(0x30)
	cmd = append(cmd, data...)
	return
}

func (this *CmodeMaster) Write(conn io.Writer, cmd []byte) (n int, err error) {

	//校验
	fc1, fc2 := hostlink.FCS(cmd)
	cmd = append(cmd, fc1, fc2, 0x2A, 0x0D)
	n, err = conn.Write(cmd)
	logs.Debug("S: % 2X", cmd)

	return
}

func (this *CmodeMaster) Read(conn io.Reader, pnum int, ifbit bool) (data []byte, err error) {
	codecount := 11 //11长度的固定字节
	var length int
	if ifbit {
		length = pnum*2 + codecount //每个bit占2个字节
	} else {
		length = pnum*4 + codecount //每个寄存器占4个字节
	}
	data = make([]byte, length)
	_, err = sock.ReadTimeout(conn, data, 200)
	if err != nil {
		logs.Error(err)
		return
	}
	logs.Debug("R: % 2X", data)

	//校验
	buf, err := this.CheckData(data)
	if err != nil {
		return
	}
	return buf, err
}

func (this *CmodeMaster) CheckData(data []byte) (buf []byte, err error) {
	l := len(data)
	if l <= 11 {
		err = errors.New("The Sizeof data is error")
		logs.Info(err)
		return
	}
	if data[0] != hostlink.HK_TITLE[0] { //
		err = errors.New(fmt.Sprintf("Ask Title is wrong.right Ask Title = %d ,but receved = %d", 64, data[0]))
		logs.Info(err)
		return
	}
	if data[1] != byte(this.UintNum[0]) || data[2] != byte(this.UintNum[1]) {
		err = errors.New(fmt.Sprintf("ASK UNIT num is error:%d %d", data[1], data[2]))
		logs.Info(err)
		return
	}
	if data[5] != byte(0x30) || data[6] != byte(0x30) {
		err = errors.New(fmt.Sprintf("ASK end code  is error: %d %d", data[1], data[2]))
		logs.Info(err)
		return
	}
	//校验
	fc1, fc2 := hostlink.FCS(data[:l-4])
	if data[l-4] != fc1 || data[l-3] != fc2 {
		logs.Info(fc1, fc2)
		err = errors.New(fmt.Sprintf("the fcs code error FCS1 = % 2X ,FCS2 = %2X ,fc1= % 2X, fc2 = %2X ", data[l-4], data[l-3], fc1, fc2))
		return
	}
	return data[6 : l-4], err
}
